package com.zyh.scs.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyh.scs.admin.api.constant.RechargeChannelEnum;
import com.zyh.scs.admin.api.dto.EarlyWarnDTO;
import com.zyh.scs.admin.api.entity.*;
import com.zyh.scs.admin.api.utils.UserTypeToNameUtil;
import com.zyh.scs.admin.api.vo.UserEarlyWarnVO;
import com.zyh.scs.admin.mapper.*;
import com.zyh.scs.admin.service.UserEarlyWarnService;
import com.zyh.scs.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author hwh
 * @ClassName: 预警提示 接口实现类$
 * @Description: $
 * @Date $
 * @Version 1.0
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserEarlyWarnServiceImpl extends ServiceImpl<UserEarlyWarnMapper, UserEarlyWarn> implements UserEarlyWarnService {

    private final UserEarlyWarnMapper userEarlyWarnMapper;

    private final SysUserMapper sysUserMapper;

    private final UserTransactionMapper userTransactionMapper;

    private final UserPaymentMapper userDeductionMapper;

    private final UserRechargeRecordMapper userRechargeRecordMapper;

    private final RedissonClient redissonClient;

    @Override
    public List<UserEarlyWarnVO> getResultList() {
        List<UserEarlyWarn> userWarnList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery().eq(UserEarlyWarn::getEarlyType, "1").eq(UserEarlyWarn::getResult, "1").eq(UserEarlyWarn::getDelFlag, 0).eq(UserEarlyWarn::getEarlyType, "1").orderByDesc(UserEarlyWarn::getCreateTime));
        List<UserEarlyWarnVO> userEarlyWarnVOList = new ArrayList<>();
        userWarnList.forEach(a -> {
            UserEarlyWarnVO userEarlyWarnVO = new UserEarlyWarnVO();
            //通过新数据找到老数据
            List<UserEarlyWarn> userEarlyOldList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery().eq(UserEarlyWarn::getNewId, a.getWarnId()).eq(UserEarlyWarn::getDelFlag, 0).eq(UserEarlyWarn::getEarlyType, "2").orderByDesc(UserEarlyWarn::getCreateTime));
            List<UserEarlyWarn> userEarlyNewList = new ArrayList<>();
            userEarlyNewList.add(a);
            userEarlyWarnVO.setUserEarlyNewList(userEarlyNewList);
            userEarlyWarnVO.setUserEarlyOldList(userEarlyOldList);
            userEarlyWarnVO.setRepeatField(a.getRepeatField());
            userEarlyWarnVOList.add(userEarlyWarnVO);
        });
        return userEarlyWarnVOList;
    }

    @Override
    public List<UserEarlyWarnVO> getHistoryAccount() {
        List<UserEarlyWarn> userWarnList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                .in(UserEarlyWarn::getResult, "2", "3", "4")
                .eq(UserEarlyWarn::getDelFlag, 0)
                .eq(UserEarlyWarn::getEarlyType, "1")
                .orderByDesc(UserEarlyWarn::getResultTime));
        List<UserEarlyWarnVO> userEarlyWarnVOList = new ArrayList<>();
        userWarnList.forEach(a -> {
            UserEarlyWarnVO userEarlyWarnVO = new UserEarlyWarnVO();
            //通过新数据找到老数据
            List<UserEarlyWarn> userEarlyOldList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                    .eq(UserEarlyWarn::getNewId, a.getWarnId()).eq(UserEarlyWarn::getDelFlag, 0)
                    .eq(UserEarlyWarn::getEarlyType, "2")
                    .orderByDesc(UserEarlyWarn::getResultTime));
            List<UserEarlyWarn> userEarlyNewList = new ArrayList<>();
            userEarlyNewList.add(a);
            userEarlyWarnVO.setUserEarlyNewList(userEarlyNewList);
            userEarlyWarnVO.setUserEarlyOldList(userEarlyOldList);
            userEarlyWarnVO.setRepeatField(a.getRepeatField());
            userEarlyWarnVO.setResultTime(a.getResultTime());
            userEarlyWarnVO.setOperateId(a.getOperateId());
            SysUser sysUser = sysUserMapper.selectByGuid(a.getOperateId());
            if (sysUser != null) {
                userEarlyWarnVO.setOperateName(StrUtil.isNotBlank(sysUser.getUsername()) ? sysUser.getUsername() : "");
            }
            userEarlyWarnVO.setResult(a.getResult());
            userEarlyWarnVOList.add(userEarlyWarnVO);
        });
        return userEarlyWarnVOList;
    }

    @Override
    public boolean getMerge(EarlyWarnDTO earlyWarnDTO) {
        //新账号
        if ("2".equals(earlyWarnDTO.getResult())) {
            UserEarlyWarn newEarly = userEarlyWarnMapper.selectById(earlyWarnDTO.getNewId());
            UserEarlyWarn oldEarly = userEarlyWarnMapper.selectById(earlyWarnDTO.getOldId());
            //旧账号list
            LambdaQueryWrapper<UserEarlyWarn> queryWrapper = new LambdaQueryWrapper<>();
            if ("1".equals(newEarly.getEarlyType())) {
                queryWrapper.eq(UserEarlyWarn::getNewId, newEarly.getWarnId());
            }
            if ("1".equals(oldEarly.getEarlyType())) {
                queryWrapper.eq(UserEarlyWarn::getNewId, oldEarly.getWarnId());
            }
            queryWrapper.eq(UserEarlyWarn::getDelFlag, "0")
                    .orderByDesc(UserEarlyWarn::getCreateTime);
            List<UserEarlyWarn> userEarlyList = userEarlyWarnMapper.selectList(queryWrapper);
            if ("1".equals(newEarly.getEarlyType())) {
                userEarlyList.add(newEarly);
            }
            if ("1".equals(oldEarly.getEarlyType())) {
                userEarlyList.add(oldEarly);
            }


            if (earlyWarnDTO.getResult().equals("2")) {
                SysUser newUser = sysUserMapper.selectById(newEarly.getUserId());
                SysUser oldUser = sysUserMapper.selectById(oldEarly.getUserId());

                //先给新账号加锁
                RLock lockNew = redissonClient.getLock("getAccountLock" + newUser.getGuid());
                RLock lockOld = redissonClient.getLock("getAccountLock" + oldUser.getGuid());


                try {
                    // 直接获取锁，阻塞式
                    lockNew.lock();
                    lockOld.lock();
                    //重新查询用户信息-避免锁失效
                    newUser = sysUserMapper.selectById(newEarly.getUserId());
                    oldUser = sysUserMapper.selectById(oldEarly.getUserId());
                    //合并到该账号
                    if (Objects.equals(earlyWarnDTO.getWarnId(), earlyWarnDTO.getNewId())) {
                        //合并到新账户
                        //先合并餐补
                        if (oldUser.getCardAccount().compareTo(BigDecimal.ZERO) != 0) {
                            BigDecimal cardAccount = oldUser.getCardAccount();
                            sysUserMapper.incrByCardAccount(newUser.getGuid(), cardAccount, LocalDateTime.now());
                            //生成充值流水和退款流水
                            insertRechargeRecord(newUser, "1", cardAccount);
                            insertDeduction(oldUser, "1", cardAccount);
                            //修改账户记录，便于后面的现金合并记录
                            oldUser.setCardAccount(BigDecimal.ZERO);
                            newUser.setCardAccount(newUser.getCardAccount().add(cardAccount));
                        }
                        //合并现金
                        if (oldUser.getCashAccount().compareTo(BigDecimal.ZERO) != 0) {
                            BigDecimal cashAccount = oldUser.getCashAccount();
                            oldUser.setCashAccount(BigDecimal.ZERO);
                            sysUserMapper.incrByCashAccount(newUser.getGuid(), cashAccount, LocalDateTime.now());
                            //生成充值流水和退款流水
                            insertRechargeRecord(newUser, "2", cashAccount);
                            insertDeduction(oldUser, "2", cashAccount);
                        }
                        //冻结老账号  启用新账户
                        oldUser.setCashAccount(BigDecimal.ZERO);
                        oldUser.setCardAccount(BigDecimal.ZERO);
                        oldUser.setCardState("2");
                        oldUser.setCashState("2");
                        oldUser.setPullStatus(1);
                        oldUser.setLockFlag("9");
                        newUser.setCashAccount(null);
                        newUser.setCardAccount(null);
                        newUser.setCardState("1");
                        newUser.setCashState("1");
                        newUser.setLockFlag("0");
                        newUser.setPullStatus(1);
                        sysUserMapper.updateById(oldUser);
                        sysUserMapper.updateById(newUser);
                    } else if (Objects.equals(earlyWarnDTO.getWarnId(), earlyWarnDTO.getOldId())) {
                        //合并到旧账号 先合并餐补
                        if (newUser.getCardAccount().compareTo(BigDecimal.ZERO) != 0) {
                            BigDecimal cardAccount = newUser.getCardAccount();
                            sysUserMapper.incrByCardAccount(oldUser.getGuid(), cardAccount, LocalDateTime.now());
                            //生成充值流水和退款流水
                            insertRechargeRecord(oldUser, "1", cardAccount);
                            insertDeduction(newUser, "1", cardAccount);
                            //修改账户记录，便于后面的现金合并记录
                            newUser.setCardAccount(BigDecimal.ZERO);
                            oldUser.setCardAccount(oldUser.getCardAccount().add(cardAccount));
                        }
                        //合并现金
                        if (newUser.getCashAccount().compareTo(BigDecimal.ZERO) != 0) {
                            BigDecimal cashAccount = newUser.getCashAccount();
                            sysUserMapper.incrByCashAccount(oldUser.getGuid(), cashAccount, LocalDateTime.now());
                            //生成充值流水和支付流水退款流水
                            insertRechargeRecord(oldUser, "2", cashAccount);
                            insertDeduction(newUser, "2", cashAccount);
                        }
                        //冻结新账号  启用老账户
                        newUser.setCashAccount(BigDecimal.ZERO);
                        newUser.setCardAccount(BigDecimal.ZERO);
                        newUser.setCardState("2");
                        newUser.setCashState("2");
                        newUser.setLockFlag("9");
                        newUser.setPullStatus(1);
                        oldUser.setCashAccount(null);
                        oldUser.setCardAccount(null);
                        oldUser.setCardState("1");
                        oldUser.setCashState("1");
                        oldUser.setLockFlag("0");
                        oldUser.setPullStatus(1);
                        sysUserMapper.updateById(oldUser);
                        sysUserMapper.updateById(newUser);
                    }
                    SysUser sysUserSecurity = sysUserMapper.selectById(SecurityUtils.getUser().getId());
                    userEarlyList.forEach(a -> {
                        a.setResult("2");
                        a.setResultTime(LocalDateTime.now());
                        if (sysUserSecurity != null) {
                            a.setCreateBy(sysUserSecurity.getUsername());
                            a.setOperateId(sysUserSecurity.getGuid());
                        }
                        userEarlyWarnMapper.updateById(a);
                    });
                } catch (Exception e) {
                    log.error("预警合并异常", e);
                } finally {
                    if (lockOld.isLocked() && lockOld.isHeldByCurrentThread()) {
                        lockOld.unlock();
                    }
                    if (lockNew.isLocked() && lockNew.isHeldByCurrentThread()) {
                        lockNew.unlock();
                    }
                }

            }
        }
        if ("3".equals(earlyWarnDTO.getResult())) {
            //忽略
            UserEarlyWarn userEarlyWarn = userEarlyWarnMapper.selectById(earlyWarnDTO.getNewId());
            List<UserEarlyWarn> userEarlyList = new ArrayList<>();
            if ("1".equals(userEarlyWarn.getEarlyType())) {
                userEarlyList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                        .eq(UserEarlyWarn::getNewId, userEarlyWarn.getNewId()));
                userEarlyList.add(userEarlyWarn);
            }else if ("2".equals(userEarlyWarn.getEarlyType())) {
                UserEarlyWarn warn = userEarlyWarnMapper.selectById(userEarlyWarn.getNewId());
                userEarlyList = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                        .eq(UserEarlyWarn::getNewId, userEarlyWarn.getWarnId()));
                userEarlyList.add(warn);
            }
            SysUser sysUserSecurity = sysUserMapper.selectById(SecurityUtils.getUser().getId());
            userEarlyList.forEach(a -> {
                a.setResult("3");
                a.setResultTime(LocalDateTime.now());
                if (sysUserSecurity != null) {
                    a.setCreateBy(sysUserSecurity.getUsername());
                    a.setOperateId(sysUserSecurity.getGuid());
                }
                a.setResult("3");
                userEarlyWarnMapper.updateById(a);
            });
        }
        return Boolean.TRUE;
    }


    /**
     * 生成充值流水和交易流水
     *
     * @param sysUser      用户
     * @param rechargeType 充值类型
     * @param money        充值金额
     */
    public void insertRechargeRecord(SysUser sysUser, String rechargeType, BigDecimal money) {
        UserRechargeRecord userRechargeRecord = new UserRechargeRecord();
        String rechargeStream = UserTypeToNameUtil.setRechargeStream();
        UserTransaction userTransaction = new UserTransaction();
        //餐补
        BeanUtil.copyProperties(sysUser, userRechargeRecord);
        userRechargeRecord.setCreateTime(LocalDateTime.now());
        userRechargeRecord.setLastRechargeTime(LocalDateTime.now());
        userRechargeRecord.setNotes("预警合并充值");
        userRechargeRecord.setRechargeStream(rechargeStream);
        userRechargeRecord.setRechargeChannel(RechargeChannelEnum.BACK_GROUND.getCode());
        //充值流水
        if (rechargeType.equals("1")) {
            userRechargeRecord.setCardAccount(sysUser.getCardAccount().add(money));
        } else {
            userRechargeRecord.setCashAccount(sysUser.getCashAccount().add(money));
        }
        userRechargeRecord.setRechargeNumber(money);
        userRechargeRecord.setRechargeType(rechargeType);
        userRechargeRecordMapper.insert(userRechargeRecord);
        BeanUtil.copyProperties(userRechargeRecord, userTransaction);
        userTransaction.setTransactionNumber(money);
        userTransaction.setTransactionType("6");
        userTransaction.setNotes("预警合并充值");
        userTransaction.setTransactionTime(LocalDateTime.now());
        userTransaction.setTradeType(1);
        userTransaction.setAccountType(rechargeType);
        userTransaction.setAccountType(rechargeType);
        userTransaction.setUserMealsNumber(sysUser.getUserMealsNumber());
        userTransactionMapper.insert(userTransaction);
    }


    /**
     * 生成支付流水和交易流水
     *
     * @param sysUser       用户
     * @param deductionType 退款类型
     * @param money         充值金额
     */
    public void insertDeduction(SysUser sysUser, String deductionType, BigDecimal money) {
        UserPayment userDeduction = new UserPayment();
        UserTransaction userTransaction = new UserTransaction();
        String rechargeStream = UserTypeToNameUtil.setRechargeStream();
        //退款流水
        BeanUtil.copyProperties(sysUser, userDeduction);
        userDeduction.setCreateTime(LocalDateTime.now());
        userDeduction.setPaymentChannel("3");
        userDeduction.setTransactionTime(LocalDateTime.now());
        userDeduction.setRechargeStream(rechargeStream);
        userDeduction.setNotes("预警合并支付");
        userDeduction.setPayNumber(money);
        userDeduction.setAccountType(deductionType);
        //充值流水
        if (deductionType.equals("1")) {
            userDeduction.setCardAccount(sysUser.getCardAccount().subtract(money));
        } else {
            userDeduction.setCashAccount(sysUser.getCashAccount().subtract(money));
        }
        userDeductionMapper.insert(userDeduction);
        //生成交易流水 退款
        BeanUtil.copyProperties(userDeduction, userTransaction);
        userTransaction.setTransactionNumber(money);
        userTransaction.setTransactionType("10");
        userTransaction.setAccountType(deductionType);
        userTransaction.setTransactionTime(LocalDateTime.now());
        userTransaction.setTradeType(1);
        userTransaction.setUserMealsNumber(sysUser.getUserMealsNumber());
        userTransactionMapper.insert(userTransaction);
    }
}
